﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Diagnostics;

using LowLevelGraphics.Drawing;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// This filter is used to detect circle.
    /// I created it on my own.
    /// </summary>
    public class Circle : BaseImageFilter
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Circle"/> class.
        /// </summary>
        public Circle()
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Circle"/> class.
        /// </summary>
        /// <param name="_circle">The _circle.</param>
        internal Circle(Circle _circle)
        {
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            //Prepare Image
            new RoundColors(100).Execute(_bitmap);

            UnsafeBitmap bitmap = _bitmap;

            Color color = Color.Transparent;
            Color colorCircle = Color.Transparent;
            int nX = 0;
            int nY = 0;
            int nXLeft = 0;
            int nXRight = 0;
            int nYTop = 0;
            int nYBottom = 0;
            int n1DX = 0;
            int n2DX = 0;
            int n1DY = 0;
            int n2DY = 0;
            Dictionary<Point, int> aColorPoint = new Dictionary<Point, int>();

            int x = bitmap.Width / 2;
            int y = bitmap.Height / 2;
            int nXStep = 2;
            int nYStep = 2;

            int nHeight = _bitmap.Height;
            int nWidth = _bitmap.Width;

            Bresenham bresenham = new Bresenham();

            //What does this do at the moment?
            //This creates a space of potential circles that might be found in this pic. 
            //Afterwards there should be a check if this really could be a circle.
            for (y = 0; y < nHeight; y += nYStep)
            {
                for (x = 0; x < nWidth; x += nXStep)
                {
                    color = bitmap.GetPixel(x, y);
                    colorCircle = color;
                    nX = x;
                    nY = y;
                    while (nX < nWidth && colorCircle == color)
                    {
                        colorCircle = bitmap.GetPixel(nX, nY);
                        nX++;
                    }
                    nXRight = nX;

                    colorCircle = color;
                    nX = x;
                    nY = y;
                    while (nX > -1 && colorCircle == color)
                    {
                        colorCircle = bitmap.GetPixel(nX, nY);
                        nX--;
                    }
                    nXLeft = nX;

                    colorCircle = color;
                    nX = x;
                    nY = y;
                    while (nY < nHeight && colorCircle == color)
                    {
                        colorCircle = bitmap.GetPixel(nX, nY);
                        nY++;
                    }
                    nYBottom = nY;

                    colorCircle = color;
                    nX = x;
                    nY = y;
                    while (nY > -1 && colorCircle == color)
                    {
                        colorCircle = bitmap.GetPixel(nX, nY);
                        nY--;
                    }
                    nYTop = nY;

                    n1DX = Math.Abs(x - nXLeft);
                    n2DX = Math.Abs(x - nXRight);
                    n1DY = Math.Abs(y - nYBottom);
                    n2DY = Math.Abs(y - nYTop);

                    int nDX = Math.Abs(n1DX - n2DX);
                    int nDY = Math.Abs(n1DY - n2DY);
                    //Debug.WriteLine(string.Format("n1DX: {0}, n2DX: {1}, n1DY: {2}, n2DY: {3}", n1DX, n2DX, n1DY, n2DY));

                    if (Math.Abs(nDX - nDY) < 3)                    
                    {
                        //Do a bresenham match now. 
                        int nCount = 0;
                        foreach (Point pt in bresenham.RasterCircle(_bitmap, x - n1DX, y - n1DX, n1DX))
                        {
                            if (pt.X > -1 && pt.Y > -1 && pt.X < nWidth - 1 && pt.Y < nHeight - 1)
                            {
                                if (colorCircle == bitmap.GetPixel(x, y))
                                {
                                    nCount++;
                                    if (nCount > 10)
                                    {
                                        aColorPoint.Add(new Point(x, y), n1DX);
                                        break; // leave loop if found
                                    }
                                }
                            }
                        }
                    }
                }
            }

            bitmap.Clear();

            bitmap.UnlockImage();

            Color[] aColor = Definitions.KnownColors;
            //TODO: old code, replace durch  new code and test
            Graphics g = Graphics.FromImage(_bitmap.InternalBitmap);
            int nIndex = 0;
            foreach (KeyValuePair<Point, int> keyValuePair in aColorPoint)
            {
                //g.FillEllipse(new SolidBrush(Color.Red), new Rectangle(keyValuePair.Key.X - keyValuePair.Value / 2, keyValuePair.Key.Y - keyValuePair.Value / 2, keyValuePair.Value, keyValuePair.Value));
                Color colorTemp = aColor[nIndex++ % aColor.Length];
                Pen pen = new Pen(colorTemp,1);
                g.DrawEllipse(pen, new Rectangle(keyValuePair.Key.X - keyValuePair.Value / 2, keyValuePair.Key.Y - keyValuePair.Value / 2, keyValuePair.Value, keyValuePair.Value));
                pen.Dispose();
            }
            g.Dispose();
            bitmap.LockImage();

            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new Circle(this);
        }
    }
}
